from __future__ import absolute_import
import unittest

import json
import app.main as reformflask
import users_insert_test
from functools import wraps


def print_res(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        res = None
        try:
            res = func(*args, **kwargs)
            print("{}: {}".format(func.__name__, json.dumps(res)))
        except ValueError as e:
            print ValueError, e
        return res

    return wrapper


class FlaskTestCase(unittest.TestCase):
    def setUp(self):
        self.app = reformflask.app.test_client()
        users_insert_test.insert_admin()

    def tearDown(self):
        pass

    @print_res
    def login(self, **kwargs):
        res = self.app.post(
            '/api/user/login',
            data=json.dumps(kwargs)
        )
        print(res.status_code),
        return json.loads(res.data)

    @print_res
    def info(self, **kwargs):
        res = self.app.post(
            '/api/user/info',
            data=json.dumps(kwargs)
        )
        print(res.status_code),
        return json.loads(res.data)

    @print_res
    def logout(self, token):
        res = self.app.post(
            '/api/user/logout',
            data=json.dumps({'token': token})
        )
        print(res.status_code),
        return json.loads(res.data)

    @print_res
    def register(self, **kwargs):
        res = self.app.post(
            '/api/user/register',
            data=json.dumps(kwargs)
        )
        print(res.status_code),
        return json.loads(res.data)

    @print_res
    def user_list(self, **kwargs):
        res = self.app.post(
            '/api/user/list',
            data=json.dumps(kwargs)
        )
        print(res.status_code),
        return json.loads(res.data)

    @print_res
    def user_delete(self, **kwargs):
        res = self.app.post(
            '/api/user/delete',
            data=json.dumps(kwargs)
        )
        print(res.status_code),
        return json.loads(res.data)

    @print_res
    def status_all(self, token):
        res = self.app.post(
            '/api/device/status_all',
            data=json.dumps({"token": token})
        )
        print(res.status_code),
        return json.loads(res.data)

    @print_res
    def status(self, token):
        res = self.app.post(
            '/api/device/status',
            data=json.dumps({"token": token})
        )
        print(res.status_code),
        return json.loads(res.data)

    @print_res
    def code_submit(self, **kwargs):
        res = self.app.post(
            '/api/code/submit',
            data=json.dumps(kwargs)
        )
        print(res.status_code),
        return json.loads(res.data)

    @print_res
    def code_get(self, **kwargs):
        res = self.app.post(
            '/api/code/get',
            data=json.dumps(kwargs)
        )
        print(res.status_code),
        return json.loads(res.data)

    @print_res
    def user_history(self, **kwargs):
        res = self.app.post(
            '/api/user/history',
            data=json.dumps(kwargs)
        )
        print(res.status_code),
        return json.loads(res.data)

    def test_all(self):
        self.login(id='201594095', xxx='xxx')
        user_not_exist_login = self.login(id=888888, password='888888')
        assert user_not_exist_login["msg"] == "user_not_exist"

        admin_login = self.login(id='201594095', password='19961231')
        assert "token" in admin_login["data"]
        admin_token = admin_login["data"]["token"]
        assert admin_login["data"]["user_group"] == 0
        self.user_delete(token=admin_token, users=[201594064, 201594095])
        assert self.register(token=admin_token, target_user_id=201594064, target_user_password="123456")["data"] == "register"

        normal_login = self.login(id=201594064, password='123456')
        assert "token" in normal_login["data"]
        assert normal_login["data"]["user_group"] == 1
        normal_token = normal_login["data"]["token"]

        assert self.info(token=normal_token)["data"]["user_group"] == 1

        assert self.register(token=normal_token, target_user_id=201594082, target_user_password="123456", device=15)["msg"] == "user_group_not_allowed"
        self.register(token=admin_token, target_user_id=201594082, target_user_password="123456", device=15)
        # revise password will drop all tokens
        before_revise_token = self.login(id='201594082', password="123456")
        assert self.register(token=admin_token, target_user_id=201594082, target_user_password="1234567")["data"] == "revise"
        assert self.status(token=before_revise_token)["msg"] == "need_login"
        assert self.register(token=admin_token, target_user_id=201594082, target_user_password="123")[
                   "msg"] == "password_format_error"
        assert self.register(token=admin_token, target_user_id=201594082, device=19)["data"] == "revise"
        assert self.register(token=admin_token, target_user_id=201594082, target_user_password="123456", device=15)["data"] == "revise"
        assert self.register(token=admin_token, target_user_id=201594064, device=15)["msg"] == "device_duplicated"

        assert len(self.user_list(token=admin_token)["data"]) > 0

        assert self.status_all(normal_token)["msg"] == "user_group_not_allowed"
        assert len(self.status_all(admin_token)["data"]) == 20

        assert self.status(admin_token)["msg"] == "user_group_not_allowed"
        assert self.status(normal_token)["msg"] == "device_not_binded"

        device_normal_token = self.login(id=201594082, password="123456")["data"]["token"]
        assert "device" in self.status(device_normal_token)["data"]

        self.code_submit(token=device_normal_token, code="""
#include <cstdio>
#include <iostream>
using namespace std;
int onUpdate(int generator_i, int generator_u, int payload_i, int payload_u)
{
    return 50;
}
""")
        assert self.status_all(admin_token)["data"][0]["code_status"] == "idle"
        assert self.status_all(admin_token)["data"][14]["code_status"] == "submitted"

        assert len(self.code_get(token=device_normal_token)["data"]) > 0

        assert self.user_history(token=device_normal_token)["status"] is True

        self.logout(normal_token)
        assert len(self.user_delete(token=admin_token, users=[201594064, 201594095])["data"]) > 0
        assert self.user_delete(token=admin_token, users=[201594064])["data"][0]["status"] is False
        assert self.status(normal_token)["msg"] == "need_login"

        self.logout(admin_token)
        self.logout(device_normal_token)

        assert self.status_all(admin_token)["msg"] == "need_login"
        assert self.register(token=admin_token, target_user_id=201594082, target_user_password="123456", device=15)["msg"] == "need_login"
